import java.io.FileNotFoundException;
import java.util.ArrayList;

import javax.swing.JFrame;

import math.Color3f;
import math.Point3f;
import math.Ray;
import math.Triangle;
import math.Vector3f;
import drawing.CgPanel;
import drawing.HitRecord;
import drawing.Scene;
import drawing.SceneBuilder;
import drawing.ZBuffer;

public class Main {

	private JFrame frame;
	private CgPanel panel;
	private SceneBuilder builder;
	private Scene scene;
	private float top, bottom, left, right, far, near, nx, ny;

	public static void main(String[] args) {
		try {
			Main tracer = new Main();
//			 tracer.draw();
			tracer.rasterize();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public Main() throws FileNotFoundException, InterruptedException {
		nx = 512;
		ny = 512;
		initializeFrame();
		buildScene();
		createFieldOfView();
	}

	private void buildScene() throws FileNotFoundException {
		builder = new SceneBuilder();
		scene = builder.loadScene("/XML/test2.sdl");
	}

	private void initializeFrame() throws InterruptedException {
		frame = new JFrame();
		frame.setSize((int) nx, (int) ny);
		panel = new CgPanel();
		frame.getContentPane().add(panel);
		frame.setVisible(true);
		Thread.sleep(500);
		panel.repaint();
	}

	private void createFieldOfView() {
		near = 1;
		far = 10000;
		top = (float) Math.tan(Math.toRadians((this.scene.getCurrentCamera()
				.getFovy()) / 2.0));
		bottom = -top;
		right = -(nx / ny) * top;
		left = -right;
	}

	public void draw() throws InterruptedException {
		Thread.sleep(500);
		Vector3f[] uvw = this.scene.getCurrentCamera().getUVW();
		for (int i = 0; i < nx; i++) {
			for (int j = 0; j < ny; j++) {
				float us = (float) (left + ((right - left) * (i + 0.5) * (1 / nx)));
				float vs = (float) (bottom + ((top - bottom) * (j + 0.5) * (1 / ny)));
				float ws = near;
				Point3f eye = (Point3f) this.scene.getCurrentCamera()
						.getOrigin().clone();
				Vector3f direction = new Vector3f(eye.x, eye.y, eye.z);
				direction = direction.add(uvw[0].scale(us));
				direction = direction.add(uvw[1].scale(vs));
				direction = direction.add(uvw[2].scale(ws));
				Ray ray = new Ray(eye, direction);
				System.out.println(ray);
				ArrayList<Triangle> triangles = this.scene.getTriangles();
				HitRecord permRecord = null;
				HitRecord tempRecord = null;
				float n, f;
				n = 0;
				f = 10000;
				for (Triangle triangle : triangles) {
					tempRecord = triangle.intersect(ray, n, f);
					if (permRecord == null && tempRecord != null) {
						permRecord = tempRecord;
						f = permRecord.getT();
					} else if (permRecord != null && tempRecord != null
							&& tempRecord.getT() < permRecord.getT()) {
						permRecord = tempRecord;
						f = permRecord.getT();
					}
				}
				if (permRecord != null) {
					Color3f color = this.scene.getColor(permRecord);
					if(color != null)
						panel.drawPixel(i, j, color.x, color.y, color.z);
					else
						panel.drawPixel(i, j, this.scene.getBackgroundColor().x,
								this.scene.getBackgroundColor().y, this.scene
										.getBackgroundColor().z);
				} else {
					panel.drawPixel(i, j, this.scene.getBackgroundColor().x,
							this.scene.getBackgroundColor().y, this.scene
									.getBackgroundColor().z);
				}
			}
		}
		Thread.sleep(500);
		panel.repaint();
		Thread.sleep(500);
		panel.flush();
		System.out.println("Done");
	}

	public void rasterize() throws InterruptedException {
		Vector3f[] uvw = this.scene.getCurrentCamera().getUVW();
		ZBuffer zb = new ZBuffer((int) nx, (int) ny);
		Ray eyeRay;
		HitRecord hitRecord;

		ArrayList<Triangle> triangles = this.scene.getTriangles();
		for (Triangle triangle : triangles) {
			for (int j = 0; j < ny; j++) {
				for (int i = 0; i < nx; i++) {

					float us = (float) (left + ((right - left) * (i + 0.5) * (1 / nx)));
					float vs = (float) (bottom + ((top - bottom) * (j + 0.5) * (1 / ny)));
					float ws = near;
					Point3f eye = (Point3f) this.scene.getCurrentCamera()
							.getOrigin().clone();
					Vector3f direction = new Vector3f(eye.x, eye.y, eye.z);
					direction = direction.add(uvw[0].scale(us));
					direction = direction.add(uvw[1].scale(vs));
					direction = direction.add(uvw[2].scale(ws));
					eyeRay = new Ray(eye, direction);
					float n, f;
					n = 0;
					f = Float.MAX_VALUE;
					hitRecord = triangle.intersect(eyeRay, n, f);
					if (hitRecord != null) {
						if (hitRecord.getT() < zb.getZValue(i, j)) {
							zb.setZValue(i, j, hitRecord.getT());
							Color3f color = this.scene.getColor(hitRecord);
							panel.drawPixel(i, j, color.x,
									color.y, color.z);
						}
					}
				}
			}

		}
		System.out.println("Done");
	}
}
